package com.simple.common.framework.context;

import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.TtlCallable;
import com.alibaba.ttl.TtlRunnable;
import com.alibaba.ttl.threadpool.TtlExecutors;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Supplier;

/**
 * @author yasud
 * @date 2020年05月27日 09:05
 * @description
 */
@Component
public class Contexts implements BeanFactoryAware, ApplicationContextAware, EnvironmentAware {

    /**
     * 自己
     */
    private static Holder _HOLDER;

    /**
     * 这个是常量
     */
    public static ApplicationContext APPLICATIONCONTEXT;

    /**
     * bean_factory
     */
    public static BeanFactory BEANFACTORY;

    /**
     * 配置文件
     */
    public static Environment ENVIRONMENT;

    /**
     *
     */
    public static ObjectMapper OBJECTMAPPER;

    /**
     *
     */
    public static Gson GSON;

    /**
     * 同一设置
     * @param objectMapper
     * @param gson
     */
    @Autowired
    public void init(ObjectMapper objectMapper,
                     Gson gson) {
        OBJECTMAPPER = objectMapper;
        GSON = gson;
        _HOLDER = new Holder();
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        BEANFACTORY = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        APPLICATIONCONTEXT = applicationContext;
    }

    @Override
    public void setEnvironment(Environment environment) {
        ENVIRONMENT = environment;
    }


    public static class Holder {

        /**
         * 初始化
         */
        private final TransmittableThreadLocal<Map<String, Object>> CURRENT_ = new TransmittableThreadLocal() {
            @Override
            protected Object initialValue() {
                return Maps.newHashMap();
            }
        };

        /**
         * 支持 跨 线程池 访问threadLocal
         * @param executorService
         * @return
         */
        public static ExecutorService wrapperWithThreadLocal(ExecutorService executorService) {
            return TtlExecutors.getTtlExecutorService(executorService);
        }

        /**
         * 支持 跨 线程池 访问threadLocal
         * @param scheduledExecutorService
         * @return
         */
        public static ScheduledExecutorService wrapperScheduled(ScheduledExecutorService scheduledExecutorService) {
            return TtlExecutors.getTtlScheduledExecutorService(scheduledExecutorService);
        }

        /**
         *
         * @param callable
         * @param <R>
         * @return
         */
        public static <R> Callable<R> call(Callable<R> callable) {
            return TtlCallable.get(callable);
        }

        public static Runnable run(Runnable runnable) {
            return TtlRunnable.get(runnable);
        }

        /**
         *
         * @param supplier
         * @param <T>
         */
        public <T> void run(Supplier<T> supplier) {
            Object capture = TransmittableThreadLocal.Transmitter.capture();
            TransmittableThreadLocal.Transmitter.runSupplierWithCaptured(capture, supplier);
        }

        public void setValue(String key, Object v) {
            Map<String, Object> map = CURRENT_.get();
            map.put(key, v);
        }

        public <R> R getValue(String key) {
            Map<String, Object> map = CURRENT_.get();
            return (R)map.get(key);
        }
    }

    /**
     * 返回 跨线程 threadlocal 实现 当前获取自己的运行上下文
     * @return
     */
    public static Holder _holder() {
        return _HOLDER;
    }

}
